//gigaCode
#include <Arduino.h>
#include <WiFi.h> // library to connect to Wi-Fi network
#include "NTPClient.h"
#include <WiFiUdp.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <BH1750.h> 
#include "Timer.h"
#include "alarm.h"
#include "ObjectM.h"
#include "PointLed.h"

const uint16_t dTimerLight{250};

Timer tRadar(100);
Timer timerLight(dTimerLight);

ObjectM arrObj[3];
//------------------------------------------------------------------------------------------------------------
//TODO: добавить кнопку для включения максимального света, повторное нажатие отключает максимальный свет.
//выход из зоны также отключает максимальный свет.
//------------------------------------------------------------------------------------------------------------
const uint8_t ledR{27};
const uint8_t ledG{26};
const uint8_t ledB{25};
//-------------------------------------------------------------------------------------------------------
PointLed led1(ledR, 0, arrObj, 10, 1100);
PointLed led2(ledG, 1, arrObj, 1000, 2000);
PointLed led3(ledB, 2, arrObj, 1900, 3000);
PointLed* arrLed[3]{&led1, &led2, &led3};
//---------------------------------------------
// WiFiUDP ntpUDP;
// NTPClient timeClient(ntpUDP, "pool.ntp.org", 10800, 3600000);
//---------------------------------------------
const char* ssid = "ivanych";
const char* password = "stroykomitet";
WiFiClient espClient;
PubSubClient client(espClient);
//-----------------------------------------------------
const char* mqtt_server = "192.168.1.34";
const char* msgMotion = "kitchen/motion";
const char* msgPresence = "kitchen/presence";
const char* msgLight = "kitchen/light";
const char* msgMaxLightOn = "kitchen/maxLightOn";
const char* msgMaxLightOff = "kitchen/maxLightOff";
const char* msgHSMotion = "hall_small/motion";
//-----------------------------------------------------------
BH1750 lightMeter(0x23);  //0x5c 23
float lux{8000};  //яркость света в помещении
float luxOld{0};  //предыдущее значение
// //-------------------------------------------------------------------------------------------------------
// Alarm ledAlR(ledR);
// Alarm ledAlG(ledG);
// Alarm ledAlB(ledB);
// Alarm* arrAlarm[3]{&ledAlR, &ledAlG, &ledAlB};
//--------------------------------------
void callback(char* topic, byte* payload, unsigned int length) {
  String str = {};
  String strTopic = topic;
  String sOut{};

  for (int i = 0; i < length; i++) {
    str += (char)payload[i];
  }

  if(strTopic == msgHSMotion){
    // light_1.extLightOn();
  } 
  else if(strTopic == msgMaxLightOn){
    for(auto led: arrLed){
      led->setMaxLevelOn();
    }
  } else if(strTopic == msgMaxLightOff){
    for(auto led: arrLed){
      led->setMaxLevelOff();
    }
  }
  // } else if(strTopic == lightNightOn){
  // } else if(strTopic == lightNightOff){
  // }
}
//-----------------------------------
void reconnect_mqtt() {
  // Loop until we're reconnected
  if(!client.connected()) {
    while (!client.connected()) {
      Serial.println("Attempting MQTT connection...");
      String clientId = "Kitchen2450";
      // Attempt to connect
      Serial.println(clientId);
      if (client.connect(clientId.c_str())) {
        Serial.println("connected");
        client.subscribe(msgMaxLightOff, 0);
        client.subscribe(msgMaxLightOn, 0);
        // client.subscribe(msgLightOn, 0);
      } else {
        Serial.print("failed, rc= ");
        Serial.print(client.state());
        Serial.println(" try again in 5 seconds");
        // Wait 5 seconds before retrying
        delay(5000);
      }
    }
  } else {
    client.loop();  //mqtt
  }
}
//------------------------------------------------------------------------------------------------------------
void setup() {
  Serial.begin(115200); //Feedback over Serial Monitor
  Serial.println(F("=========================== ptr =="));
  Wire.begin();
  // Wire.setClock(400000); // use 400 kHz I2C

  Serial2.begin (256000, SERIAL_8N1, 16, 17); //UART for monitoring the radar
  delay(500);
  WiFi.begin(ssid, password); // initialise Wi-Fi and wait
  while (WiFi.status() != WL_CONNECTED){
      Serial.print(".");
      delay(500);
  }
  // timeClient.begin();
  // timeClient.update();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  reconnect_mqtt();
  //---------------------------
  if (lightMeter.begin()) {//BH1750::CONTINUOUS_HIGH_RES_MODE)) {
    Serial.println(F("BH1750 Advanced begin"));
  }
  else {
    Serial.println(F("Error initialising BH1750"));
    while(1);
  }
}
//------------------------------------------------------------------------------------------------------------
void outByte(uint8_t n){
  if(n < 10)
    Serial.print("0");
  Serial.print(n, HEX);
}
//------------------------------------------------------------------------------------------------------------
void outHexArray(uint8_t *byteArray, int size = 26){
  for (int i = 0; i < size; i++) {
    outByte(byteArray[i]);
    if(i % 2 > 0)
      Serial.print(" ");
  }
  Serial.println();
}
//------------------------------------------------------------------------------------------------------------
int getRadar(){
  int i = 0;
  while(Serial2.available()){
    if (Serial2.read()==0xAA && Serial2.read()==0xFF) {
      uint8_t byteArray[28];
      int nBytes = Serial2.readBytes(byteArray,28);
      i = 2;
      uint16_t m{0};
      for(auto& obj: arrObj){
        obj.setParam(byteArray, i);
        // arrAlarm[m++] -> setDuration(obj.setParam(byteArray, i));
      }
    }
  }
  return i;
}
//-----------------------------------------------------------------------------------------------------------
//....... измерение освещённости
void measurmentLight(){
  if (timerLight.getTimer() && lightMeter.measurementReady()) {
    lux = lightMeter.readLightLevel();
    timerLight.setTimer(dTimerLight);
    if(abs(lux - luxOld) > 5){
      client.publish(msgLight, String(lux).c_str());
      luxOld = lux;
    }
  }
}
//------------------------------------------------------------------------------------------------------------
void loop() {
  reconnect_mqtt();
  if(tRadar.getTimer()){
    tRadar.setTimer();
    getRadar();
    for(auto& aa: arrLed){
      aa -> setDist();
    }
  }
  measurmentLight();
  for(auto& aa: arrLed){
    aa -> cycle();
  }

}
